package com.pulse.common.utils.sor;

import com.alibaba.fastjson2.JSONObject;
import com.pulse.common.utils.gzip.GzipUtil;
import com.pulse.common.utils.sor.domain.*;
import com.pulse.common.utils.sor.make.MakeSor;
import org.apache.xmlbeans.XmlSimpleList;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

public class Sor {
    public static Map<String,Object> parse(MultipartFile file) {
        SorInfo sorInfo = new SorInfo();
        Map<String,Object> res = new HashMap<>();
        res.put("status","ok");
        res.put("message","");
        res.put("sorInfo",sorInfo);

        // 判断文件是否存在
        if(file.isEmpty()){
            res.put("status","nok");
            res.put("message","文件为空");
            return res;
        }

        try(InputStream fh = file.getInputStream()){
            BufferedInputStream bfh = null;
            // 使用 BufferedInputStream 包装 InputStream
            // 以便支持 mark 和 reset 操作
//            if (!fh.markSupported()) {
                bfh = new BufferedInputStream(fh);
//            }


            sorInfo.setFilename(file.getOriginalFilename());

            // Map block
            res.put("status",MapBlock.process(bfh,sorInfo));
            if(!res.get("status").toString().equals("ok")){
                res.put("message","Map block解析失败");
                return res;
            }

            // 所有其他块
            List<Block> klist = new ArrayList<>();
            klist.add(sorInfo.getBlocks().getGenParams());
            klist.add(sorInfo.getBlocks().getSupParams());
            klist.add(sorInfo.getBlocks().getFxdParams());
            klist.add(sorInfo.getBlocks().getKeyEvents());
            klist.add(sorInfo.getBlocks().getDataPts());
            klist.add(sorInfo.getBlocks().getCksum());
            for (Block other : sorInfo.getBlocks().getOthers()) {
                klist.add(other);
            }

            List<Block> sortedList = klist.stream()
                    .sorted(Comparator.comparingInt(Block::getOrder))
                    .collect(Collectors.toList());

            for(Block refBlock : sortedList){
                String blockName = refBlock.getName();

                switch (blockName){
                    case "GenParams":
                        res.put("status", GenParams.process(bfh, sorInfo));
                        break;
                    case "SupParams":
                        res.put("status", SupParams.process(bfh, sorInfo));
                        break;
                    case "FxdParams":
                        res.put("status", FxdParams.process(bfh, sorInfo));
                        break;
                    case "DataPts":
                        res.put("status", DataPts.process(bfh, sorInfo));
                        break;
                    case "KeyEvents":
                        res.put("status", KeyEvents.process(bfh, sorInfo));
                        break;
                    case "Cksum":
                        res.put("status", Cksum.process(bfh, sorInfo));
                        break;
                    default:
                        Parts.slurp(bfh, blockName, sorInfo);
                        res.put("status", "ok");
                        break;
                }

                // 如果有错误立即停止
                if(!res.get("status").toString().equals("ok")){
                    break;
                }
            }
        }
        catch (Exception e){
            res.put("status","nok");
            res.put("message",e.getMessage());
        }

        return res;

    }

    public static Map<String,Object> parse(Path path) {
        SorInfo sorInfo = new SorInfo();
        Map<String,Object> res = new HashMap<>();
        res.put("status","ok");
        res.put("message","");
        res.put("sorInfo",sorInfo);

        try(InputStream fh = Files.newInputStream(path)){
            BufferedInputStream bfh = null;
            // 使用 BufferedInputStream 包装 InputStream
            // 以便支持 mark 和 reset 操作
//            if (!fh.markSupported()) {
            bfh = new BufferedInputStream(fh);
//            }

            sorInfo.setFilename(path.getFileName().toString());

            // Map block
            res.put("status",MapBlock.process(bfh,sorInfo));
            if(!res.get("status").toString().equals("ok")){
                res.put("message","Map block解析失败");
                return res;
            }

            // 所有其他块
            List<Block> klist = new ArrayList<>();
            klist.add(sorInfo.getBlocks().getGenParams());
            klist.add(sorInfo.getBlocks().getSupParams());
            klist.add(sorInfo.getBlocks().getFxdParams());
            klist.add(sorInfo.getBlocks().getKeyEvents());
            klist.add(sorInfo.getBlocks().getDataPts());
            klist.add(sorInfo.getBlocks().getCksum());
            for (Block other : sorInfo.getBlocks().getOthers()) {
                klist.add(other);
            }

            List<Block> sortedList = klist.stream()
                    .sorted(Comparator.comparingInt(Block::getOrder))
                    .collect(Collectors.toList());

            for(Block refBlock : sortedList){
                String blockName = refBlock.getName();

                switch (blockName){
                    case "GenParams":
                        res.put("status", GenParams.process(bfh, sorInfo));
                        break;
                    case "SupParams":
                        res.put("status", SupParams.process(bfh, sorInfo));
                        break;
                    case "FxdParams":
                        res.put("status", FxdParams.process(bfh, sorInfo));
                        break;
                    case "DataPts":
                        res.put("status", DataPts.process(bfh, sorInfo));
                        break;
                    case "KeyEvents":
                        res.put("status", KeyEvents.process(bfh, sorInfo));
                        break;
                    case "Cksum":
                        res.put("status", Cksum.process(bfh, sorInfo));
                        break;
                    default:
                        Parts.slurp(bfh, blockName, sorInfo);
                        res.put("status", "ok");
                        break;
                }

                // 如果有错误立即停止
                if(!res.get("status").toString().equals("ok")){
                    break;
                }
            }
        }
        catch (Exception e){
            res.put("status","nok");
            res.put("message",e.getMessage());
        }

        return res;

    }

    public static ByteBuffer make(SorInfo info){

        ByteBuffer res = MakeSor.make(info);
        return res;
    }


    /**
     * 组装sorinfo
     *
     * @param circuitId 光路id可为null
     * @param fileName  文件名称
     * @param deviceNo 设备编号
     * @param channel 设备通号
     * @param dateTime 时间
     * @param response OTU设备返回的json
     * @return
     * @throws IOException
     */
    public static SorInfo CreateSorInfo(Long circuitId, String fileName,String deviceNo,Integer channel,Date dateTime, JSONObject response) throws IOException {
        SorInfo info = new SorInfo();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        // 文件名
        info.setFilename(fileName);

        // 文件格式版本
        info.setFormat(2);
        // 文件版本
        info.setVersion("2.00");
        // 块数量，包含Map
        info.getMapblock().setNblocks(6+1);

        // GenParams 通用参数
        GenParamsVo genParams = info.getGenParams();
        // 语言
        genParams.setLanguage("EN");
        // 电缆标识
        genParams.setCableID("");
        // 光纤标识符(这里存入的是光路id)
        String fiberId = circuitId == null ? "" : circuitId.toString();
        genParams.setFiberID(fiberId);
        // 光纤类型
        genParams.setFiberType("G.652 (standard SMF)");
        // 测试波长
        genParams.setWavelength(response.getInteger("waveLength").toString() + " nm");
        // 测试位置
        genParams.setLocationA("");
        genParams.setLocationB("");
        // 电缆代码或光纤类型
        genParams.setCableCodeOrFiberType("");
        // 测试条件
        genParams.setBuildCondition("NC (as-built)");
        // 用户偏移量
        genParams.setUserOffset("0");
        // 用户偏移距离
        genParams.setUserOffsetDistance("0");
        // 操作员名称
        genParams.setOperator("");
        // 备注
        genParams.setComments("");

        // SupParams 供应商参数
        SupParamsVo supParams = info.getSupParams();
        // 供应商名称
        supParams.setSupplier("");
        // 设备型号
        supParams.setOtdr("OTU");
        // 设备序列号
        supParams.setOtdrSN(deviceNo);
        // 模块ID
        supParams.setModule("");
        // 模块SM
        supParams.setModuleSN("");
        // 软件版本
        supParams.setSoftware("");
        // 其他
        supParams.setOther("");

        // FxdParams 固定参数
        FxdParamsVo fxdParams = info.getFxdParams();
        // 测量时间
        fxdParams.setDateTime(sdf1.format(dateTime));
        // 单位
        fxdParams.setUnit("mt (meters)");
        // 测试波长
        fxdParams.setWavelength(response.getInteger("waveLength") + " nm");
        // 采集偏移量
        fxdParams.setAcquisitionOffset("0");
        // 采集偏移距离
        fxdParams.setAcquisitionOffsetDistance("0");
        // 测量用脉冲宽度总数
        fxdParams.setNumberOfPulseWidthEntries("1");
        // 脉冲宽度
        fxdParams.setPulseWidth(response.getInteger("PW").toString() + " ns");
        // 分辨率（点间距）
        Double resolution = response.getDouble("PKP");
        fxdParams.setResolution(resolution);
        // 采用间隔
        Double sampleSpacing = fxdParams.getResolution() / 1000 * response.getDouble("IOR") / Parts.Sol;
        fxdParams.setSampleSpacing(sampleSpacing + " usec");
        // 数据点数
        Long pointCn = response.getLong("point_cnt");
        fxdParams.setNumDataPoints(pointCn.toString());
        // 折射率
        fxdParams.setIndex(response.getDouble("IOR").toString());
        // 回散系数
        fxdParams.setBc(response.getString("backScatter") + " dB");
        // 平均次数
        fxdParams.setNumAverages("0");
        // 平均时间
        fxdParams.setAveragingTime(response.getInteger("testTime") + " sec");
        // 测试范围（量程）
        double range = fxdParams.getResolution() / 1000 * pointCn;
        fxdParams.setRange(range);
        // 采集范围距离（量程）
        fxdParams.setAcquisitionRangeDistance(response.getInteger("RD").toString());
        // 前面板偏移量
        fxdParams.setFrontPanelOffset("0");
        // 噪声底电平
        fxdParams.setNoiseFloorLevel("0");
        // 噪声底缩放因子
        fxdParams.setNoiseFloorScalingFactor("1000");
        // 第一个点的功率偏移
        fxdParams.setPowerOffsetFirstPoint("0");
        // 损耗阈值
        fxdParams.setLossThr(response.get("nonReflectThreshold") + " dB");
        // 反射阈值
        fxdParams.setReflThr(response.get("reflectThreshold") + " dB");
        // 结束阈值
        fxdParams.setEotThr(response.get("finalThreshold") + " dB");
        // 跟踪类型
        fxdParams.setTraceType("ST[standard trace]");
        // 坐标点
        fxdParams.setX1("0");
        fxdParams.setY1("0");
        fxdParams.setX2("0");
        fxdParams.setY2("0");

        // KeyEvents 关键事件
        KeyEventsVo keyEvents = info.getKeyEvents();
        // 事件个数
        int numEvents = response.getInteger("event_cnt");
        keyEvents.setNumEvents(numEvents);
        // 事件
        Double endOfPrev = 0d;
        for (int i = 0; i < numEvents; i++) {
            String eventId = "event" + i;
            EventVo event = new EventVo();
            // 事件序号
            event.setEventNum(i + 1);
            // 上一事件结束位置
            event.setEndOfPrev(endOfPrev.toString());
            // 当前事件的起始位置
            Double startDist = response.getJSONObject(eventId).getDouble("startDist");
            event.setStartOfCurr(startDist.toString());
            // 当前事件的结束位置
            Long finishLocation = response.getJSONObject(eventId).getLong("finishLocation");
            Double finishDist = finishLocation.doubleValue() * fxdParams.getResolution();
            if(finishDist!=null){
                event.setEndOfCurr(finishDist.toString());
            }
            else{
                event.setEndOfCurr("0");
            }
            // 下一事件的开始位置
            String startOfNext = "0";
            if (i != numEvents - 1) {
                String nextEventId = "event" + (i + 1);
                Double startOfNextD = response.getJSONObject(nextEventId).getDouble("startDist");
                startOfNext = startOfNextD.toString();
            }
            event.setStartOfNext(startOfNext);
            // 峰值位置
            Long peakLocation = response.getJSONObject(eventId).getLong("peakLocation");
            Double peakDist = peakLocation.doubleValue() * fxdParams.getResolution();
            if(peakDist != null){
                event.setPeak(peakDist.toString());
            }else{
                event.setPeak("0");
            }

            // 事件类型
            long type = response.getJSONObject(eventId).getLong("type");
            switch ((int) type) {
                case 1:
                    event.setType("1F9999LS  {auto} reflection");
                    break;
                case 2:
                    event.setType("1E9999LS {auto} reflection");
                    break;
                case 3:
                    event.setType("1F9999LS  {auto} reflection");
                    break;
                case 4:
                    event.setType("0F9999LS  {auto}  loss/drop/gain");
                    break;
                case 5:
                    event.setType("2F9999LS  {auto}  multiple");
                    break;
                default:
                    event.setType("3B9999LS  {auto}   unknown ");
                    break;
            }
            // 事件距离
            event.setDistance(startDist.toString());
            // 斜率（分段均耗）
            Double slope = response.getJSONObject(eventId).getDouble("segAvgAtten");
            if(slope==null){
                slope = 0d;
            }
            event.setSlope(slope.toString());
            // 接头损耗
            Double spliceLoss = response.getJSONObject(eventId).getDouble("insertLoss");
            if(spliceLoss == null){
                spliceLoss = 0d;
            }
            event.setSpliceLoss(spliceLoss.toString());
            // 反射损耗
            Double returnLoss = response.getJSONObject(eventId).getDouble("returnLoss");
            if(returnLoss == null){
                returnLoss = 0d;
            }
            event.setReflLoss(returnLoss.toString());
            // 备注
            event.setComments("");

            keyEvents.getEvents().add(event);

            endOfPrev = startDist;
        }
        // 总损耗
        Double totalLoss = response.getDouble("wholeAtten");
        keyEvents.getSummary().setTotalLoss(totalLoss);
        // 损耗起始位置
        keyEvents.getSummary().setLossStart(0d);
        // 损耗结束位置
        Double wholeLen = response.getDouble("wholeLen");
        keyEvents.getSummary().setLossEnd(wholeLen);
        // 总回波损耗
        Double totalReturnLoss = response.getDouble("totallReturnLoss");
        if(totalReturnLoss!=null){
            keyEvents.getSummary().setOrl(totalReturnLoss);
        }
        else{
            keyEvents.getSummary().setOrl(0d);
        }

        // 回波损耗起始位置
        keyEvents.getSummary().setOrlStart(0d);
        // 回波损耗结束位置
        keyEvents.getSummary().setOrlFinish(wholeLen);

        // 数据点
        DataPtsVo dataPts = info.getDataPts();
        // 数据点数量
        dataPts.setNumDataPoints(pointCn);
        // 跟踪数量
        dataPts.setNumTraces(1L);
        // 第二个数据点数量
        dataPts.setNumDataPoints2(pointCn);
        // 缩放因子
        dataPts.setScalingFactor(1.0);

        // 数据
        List<String> datas = info.getDataPts().getTracedata();
        String wave = response.getString("wave");
        String hexString = GzipUtil.decompress(wave);
        // 每 4 个字符解析为一个 short
        for (int i = 0; i < hexString.length(); i += 4) {
            // 截取 4 个字符
            String hexSubstring = hexString.substring(i, Math.min(i + 4, hexString.length()));

            // 将 HEX 字符串解析为 int
            int value = Integer.parseInt(hexSubstring, 16);
            String line = String.format("%.6f", i/4 * resolution) + "\t" + String.format("%.6f", value / 1000d);
            datas.add(line);
        }

        return info;
    }
}
